<script setup lang="ts">
import { computed, onMounted, ref, watch } from 'vue'
import { uploadFile, uploadToOssWithPreSignedUrl } from '@/api/modules/system/admin/upload'

interface DrawSignProps {
  modelValue?: string // 签名图片URL
  disabled?: boolean // 是否禁用
  height?: string // 组件高度
  width?: string // 组件宽度
  borderRadius?: string // 组件边框圆角
  dir?: string // 上传图片的目录
  title?: string // 标题
  placeholder?: string // 占位文本
}

const props = withDefaults(defineProps<DrawSignProps>(), {
  modelValue: '',
  disabled: false,
  height: '150px',
  width: '150px',
  borderRadius: '12px',
  dir: 'signature',
  title: '签名',
  placeholder: '点击签名',
})

const emit = defineEmits<{
  'update:modelValue': [value: string]
  change: [value: string]
}>()

// 响应式数据
const showSignDialog = ref(false)
const isSigned = ref(false)
const isFullScreen = ref(false)
const showProgress = ref(false)
const uploadProgress = ref(0)
const signatureUrl = ref('')

// 画布相关
let ctx = null
let isButtonDown = false
let points = []
let allPoints = []

// 计算属性
const hasSignature = computed(() => {
  return !!signatureUrl.value || !!props.modelValue
})

const displayUrl = computed(() => {
  return signatureUrl.value || props.modelValue || ''
})

// 初始化画布
function initCanvas() {
  ctx = uni.createCanvasContext('signCanvas')
  // 设置画笔样式
  ctx.lineWidth = 4
  ctx.lineCap = 'round'
  ctx.lineJoin = 'round'
}

// 绘画
function draw(w?) {
  if (!ctx || points.length < 2) return

  const point1 = points[0]
  const point2 = points[1]

  if (!w) {
    allPoints[allPoints.length - 1].push(JSON.parse(JSON.stringify(points)))
  }

  points.shift()
  ctx.moveTo(point1.X, point1.Y)
  ctx.lineTo(point2.X, point2.Y)
  ctx.stroke()
  ctx.draw(true)
  isSigned.value = true
}

// 触摸开始，获取到起点
function touchStart() {
  allPoints.push([])
  if (ctx) {
    ctx.beginPath() // 每次触摸开始，开启新的路径
  }
  isButtonDown = true
}

// 触摸移动，获取到路径点
function touchMove(e) {
  if (isButtonDown && ctx) {
    let movePoint = {}
    if (e.changedTouches && e.changedTouches[0] && e.changedTouches[0].x !== undefined) {
      movePoint = { X: e.changedTouches[0].x, Y: e.changedTouches[0].y }
    } else if (e.changedTouches && e.changedTouches[0]) {
      const X = e.changedTouches[0].pageX - e.currentTarget.offsetLeft
      const Y = e.changedTouches[0].pageY - e.currentTarget.offsetTop
      movePoint = { X, Y }
    } else if (e.offsetX !== undefined) {
      // 处理鼠标事件
      movePoint = { X: e.offsetX, Y: e.offsetY }
    }

    points.push(movePoint) // 存点
    const len = points.length
    if (len >= 2) {
      draw() // 绘制路径
    }
  }
}

// 触摸结束，将未绘制的点清空防止对后续路径产生干扰
function touchEnd() {
  allPoints = allPoints.filter((e) => {
    return e.length > 0
  })
  points = []
  isButtonDown = false
}

// 清空, 传入true表示清空全部，不传传表示撤回一步
function clear(reset?: boolean) {
  if (reset) allPoints = []
  if (ctx) {
    ctx.clearRect(0, 0, 1000, 1000)
    ctx.draw(true)
  }
  isSigned.value = false
}

// 全屏
function toggleFullScreen() {
  clear(true)
  isFullScreen.value = !isFullScreen.value
  const tid = setTimeout(() => {
    initCanvas()
    clearTimeout(tid)
  }, 100)
}

// 撤回
function withdraw() {
  // 清除画布
  clear()
  if (allPoints.length <= 1) {
    allPoints = []
    points = []
    return
  }
  // 删除最后一个路径
  allPoints.pop()
  // 循环路径，重新绘制
  if (ctx) {
    allPoints.forEach((e) => {
      e.forEach((r) => {
        points = JSON.parse(JSON.stringify(r))
        draw(1)
      })
    })
  }
}

// 打开签名弹窗
function openSignDialog() {
  if (props.disabled) return
  showSignDialog.value = true
  isFullScreen.value = false
}

// 关闭签名弹窗
function closeSignDialog() {
  showSignDialog.value = false
  isFullScreen.value = false
}

// 保存签名并上传
async function saveSignature() {
  if (!isSigned.value) {
    uni.showToast({
      title: '请先签名',
      icon: 'none',
    })
    return
  }

  try {
    showProgress.value = true
    uploadProgress.value = 0

    // 将画布转为临时文件
    const res = await new Promise<UniApp.CanvasToTempFilePathRes>((resolve, reject) => {
      uni.canvasToTempFilePath({
        canvasId: 'signCanvas',
        quality: 1,
        fileType: 'png',
        success: resolve,
        fail: (error) => {
          console.error('画布转图片失败:', error)
          reject(error)
        },
      })
    })

    console.log('画布转图片成功:', res.tempFilePath)

    // 生成文件名
    const fileName = `signature_${Date.now()}.png`

    // #ifdef H5
    // H5平台：将tempFilePath转换为File对象再上传
    try {
      const response = await fetch(res.tempFilePath)
      const blob = await response.blob()
      const file = new File([blob], fileName, { type: 'image/png' })

      // 上传到OSS
      await uploadToOssWithPreSignedUrl(
        file,
        fileName,
        props.dir,
        (percent) => {
          uploadProgress.value = percent
          console.log('上传进度:', percent)
        },
        (result) => {
          console.log('上传成功:', result)
          // 更新签名URL
          signatureUrl.value = result.url
          emit('update:modelValue', result.url)
          emit('change', result.url)

          // 关闭弹窗
          showProgress.value = false
          showSignDialog.value = false
          isFullScreen.value = false

          uni.showToast({
            title: '签名已保存',
            icon: 'success',
          })
        },
        (error) => {
          console.error('上传失败:', error)
          showProgress.value = false
          uni.showToast({
            title: error.message || '保存失败',
            icon: 'none',
          })
        },
      )
    } catch (error) {
      console.error('转换文件失败:', error)
      showProgress.value = false
      uni.showToast({
        title: '文件处理失败',
        icon: 'none',
      })
    }
    // #endif

    // #ifndef H5
    // 小程序/APP平台：使用uni.uploadFile
    try {
      const uploadResult = await uploadFile({
        file: { path: res.tempFilePath } as any,
        dirTag: props.dir,
      })

      if (uploadResult.data) {
        console.log('上传成功:', uploadResult.data)
        // 更新签名URL
        signatureUrl.value = uploadResult.data.url
        emit('update:modelValue', uploadResult.data.url)
        emit('change', uploadResult.data.url)

        // 关闭弹窗
        showProgress.value = false
        showSignDialog.value = false
        isFullScreen.value = false

        uni.showToast({
          title: '签名已保存',
          icon: 'success',
        })
      } else {
        throw new Error('上传失败')
      }
    } catch (error) {
      console.error('上传失败:', error)
      showProgress.value = false
      uni.showToast({
        title: '上传失败',
        icon: 'none',
      })
    }
    // #endif
  } catch (error) {
    console.error('保存签名失败:', error)
    showProgress.value = false
    uni.showToast({
      title: '保存签名失败',
      icon: 'none',
    })
  } finally {
    uploadProgress.value = 0
  }
}

// 删除签名
function deleteSignature() {
  uni.showModal({
    title: '提示',
    content: '确定要删除签名吗？',
    success: (res) => {
      if (res.confirm) {
        signatureUrl.value = ''
        emit('update:modelValue', '')
        emit('change', '')

        uni.showToast({
          title: '已删除签名',
          icon: 'success',
        })
      }
    },
  })
}

// 预览签名
function previewSignature() {
  if (!displayUrl.value) return

  uni.previewImage({
    urls: [displayUrl.value],
    current: 0,
  })
}

// 监听modelValue变化
watch(
  () => props.modelValue,
  (newVal) => {
    if (newVal && newVal !== signatureUrl.value) {
      signatureUrl.value = newVal
    }
  },
  { immediate: true },
)

// 组件挂载时初始化
onMounted(() => {
  if (props.modelValue) {
    signatureUrl.value = props.modelValue
  }
})

// 监听弹窗状态变化
watch(
  () => showSignDialog.value,
  (newVal) => {
    if (newVal) {
      // 弹窗打开，初始化画布
      console.log('弹窗已打开，初始化画布')
      // 延迟初始化画布，确保DOM已渲染
      setTimeout(() => {
        initCanvas()
        // 如果有已有签名，清空画布
        if (ctx) {
          clear(true)
        } else {
          console.warn('画布上下文未初始化')
        }
      }, 300)
    } else {
      // 弹窗关闭，清空画布相关变量
      console.log('弹窗已关闭')
      ctx = null
      isButtonDown = false
      points = []
      allPoints = []
      isFullScreen.value = false
    }
  },
)
</script>

<template>
  <view class="draw-sign-container">
    <!-- 签名按钮/已签名显示 -->
    <view
      class="signature-box"
      :class="{ 'has-signature': hasSignature, disabled }"
      :style="{ width, height, borderRadius }"
      @click="hasSignature ? previewSignature() : openSignDialog()"
    >
      <!-- 已有签名显示 -->
      <template v-if="hasSignature">
        <image :src="displayUrl" class="signature-image" mode="aspectFit" />

        <!-- 操作按钮 -->
        <view v-if="!disabled" class="signature-actions">
          <view class="action-btn delete-btn" @click.stop="deleteSignature">
            <uni-icons type="trash" size="16" color="#fff" />
          </view>
          <view class="action-btn preview-btn" @click.stop="previewSignature">
            <uni-icons type="eye" size="16" color="#fff" />
          </view>
        </view>
      </template>

      <!-- 未签名状态 -->
      <template v-else>
        <view class="signature-placeholder">
          <uni-icons type="compose" size="24" color="#999" />
          <text class="placeholder-text">
            {{ placeholder }}
          </text>
        </view>
      </template>
    </view>

    <!-- 签名弹窗 -->
    <wd-popup
      v-model="showSignDialog"
      position="bottom"
      :close-on-click-modal="false"
      class="sign-popup"
      :safe-area-inset-bottom="true"
    >
      <view class="sign-popup-container" :class="{ 'full-screen': isFullScreen }">
        <!-- 头部 -->
        <view class="sign-header">
          <!-- 正常模式布局 -->
          <template v-if="!isFullScreen">
            <view class="header-left">
              <button class="close-btn" @click="closeSignDialog">取消</button>
            </view>
            <view class="header-title">
              {{ title }}
            </view>
            <view class="header-right">
              <button class="save-btn" :disabled="!isSigned" @click="saveSignature">保存</button>
            </view>
          </template>

          <!-- 横屏模式布局 -->
          <template v-else>
            <view class="full-screen-buttons">
              <button class="close-btn" @click="closeSignDialog">取消</button>
              <button class="save-btn" :disabled="!isSigned" @click="saveSignature">保存</button>
              <button class="tool-btn" @click="toggleFullScreen">退出全屏</button>
              <button class="tool-btn" @click="clear(true)">清空</button>
              <button class="tool-btn" @click="withdraw">撤回</button>
            </view>
          </template>
        </view>

        <!-- 签名画板 -->
        <view class="canvas-container">
          <canvas
            canvas-id="signCanvas"
            class="sign-canvas"
            :disable-scroll="true"
            @touchstart="touchStart"
            @touchmove="touchMove"
            @touchend="touchEnd"
            @mousedown="touchStart"
            @mousemove="touchMove"
            @mouseup="touchEnd"
          />
        </view>

        <!-- 工具栏 -->
        <view v-if="!isFullScreen" class="sign-tools">
          <view class="tool-btn" @click="toggleFullScreen">
            <uni-icons :type="isFullScreen ? 'top' : 'bottom'" size="18" color="#007AFF" />
            <text class="tool-text">
              {{ isFullScreen ? '退出全屏' : '全屏' }}
            </text>
          </view>
          <view class="tool-btn" @click="clear(true)">
            <uni-icons type="trash" size="18" color="#007AFF" />
            <text class="tool-text">清空</text>
          </view>
          <view class="tool-btn" @click="withdraw">
            <uni-icons type="undo-filled" size="18" color="#007AFF" />
            <text class="tool-text">撤回</text>
          </view>
        </view>
      </view>
    </wd-popup>

    <!-- 上传进度弹窗 -->
    <wd-popup
      v-model="showProgress"
      position="center"
      :close-on-click-modal="false"
      class="progress-popup"
    >
      <view class="progress-content">
        <wd-loading size="24px" />
        <text class="progress-text">保存中... {{ uploadProgress }}%</text>
      </view>
    </wd-popup>
  </view>
</template>

<style lang="scss" scoped>
$padding: 30rpx;

.draw-sign-container {
  width: 100%;
  margin-top: 20px;
  margin-bottom: 50px; // 增加底部外边距，防止被tabbar遮挡

  // 签名按钮/已签名显示
  .signature-box {
    position: relative;
    border: 2px dashed #e5e5ea;
    border-radius: 12px;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: all 0.3s;
    background: #f2f2f7;
    overflow: hidden;

    &:active {
      border-color: #007aff;
      background: rgba(0, 122, 255, 0.05);
      transform: scale(0.98);
    }

    &.has-signature {
      border: none;
      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
      background: #ffffff;

      &:active {
        transform: scale(0.95);
        box-shadow: 0 1px 4px rgba(0, 0, 0, 0.15);
      }
    }

    &.disabled {
      opacity: 0.5;
      pointer-events: none;
    }

    .signature-image {
      width: 100%;
      height: 100%;
      display: block;
      object-fit: contain;
      background: #fff;
    }

    .signature-placeholder {
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 8px;
      padding: 16px;

      .placeholder-text {
        font-size: 15px;
        color: #8e8e93;
        font-weight: 500;
      }
    }

    .signature-actions {
      position: absolute;
      top: 8px;
      right: 8px;
      display: flex;
      gap: 8px;
      opacity: 0;
      transform: translateY(-8px);
      transition: all 0.3s;

      .action-btn {
        width: 28px;
        height: 28px;
        border-radius: 14px;
        display: flex;
        align-items: center;
        justify-content: center;
        backdrop-filter: blur(20px);
        transition: all 0.2s;
        border: 1px solid rgba(255, 255, 255, 0.3);

        &:active {
          transform: scale(0.9);
        }

        &.delete-btn {
          background: rgba(255, 59, 48, 0.9);
          box-shadow: 0 2px 8px rgba(255, 59, 48, 0.3);
        }

        &.preview-btn {
          background: rgba(0, 122, 255, 0.9);
          box-shadow: 0 2px 8px rgba(0, 122, 255, 0.3);
        }
      }
    }

    // 移动端显示操作按钮
    &:active .signature-actions,
    &:hover .signature-actions {
      opacity: 1;
      transform: translateY(0);
    }

    // 为移动端添加长按效果
    @media (hover: none) {
      .signature-actions {
        opacity: 1;
        transform: translateY(0);
        top: auto;
        bottom: 8px;
        background: rgba(0, 0, 0, 0.7);
        padding: 8px;
        border-radius: 20px;
        backdrop-filter: blur(10px);
      }
    }
  }
}

// 签名弹窗
.sign-popup-container {
  background-color: #ffffff;
  border-radius: 16px 16px 0 0;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  height: 60vh;
  max-height: 60vh;
  margin-bottom: 50px;

  &.full-screen {
    height: 85vh;
    max-height: 85vh;
    border-radius: 0;
    // 横屏布局
    flex-direction: row;

    .sign-header {
      width: calc(100% / 6); // 1:5 比例
      height: 100%;
      flex-direction: column;
      border-right: 1px solid #e5e5ea;
      border-bottom: none;
      display: flex;
      justify-content: center;
      align-items: center;
      padding: 40px 16px;
      background-color: #f8f9fa;
      gap: 32px; // 按钮间距

      .header-left,
      .header-right {
        display: none; // 隐藏原来的布局结构
      }

      .header-title {
        display: none; // 隐藏标题
      }

      // 重新定义按钮布局
      .full-screen-buttons {
        display: flex;
        flex-direction: column;
        gap: 24px;
        width: 100%;
        align-items: center;
      }

      .close-btn,
      .save-btn,
      .tool-btn {
        writing-mode: horizontal-tb;
        width: 120rpx;
        height: 80rpx;
        border-radius: 12px;
        display: flex;
        align-items: center;
        justify-content: center;
        font-size: 14px;
        font-weight: 500;
        transform: rotate(90deg);
        white-space: nowrap;
        border: none;
        cursor: pointer;
        transition: all 0.2s;

        &:active {
          transform: rotate(90deg) scale(0.95);
        }
      }

      .close-btn {
        background: rgba(142, 142, 147, 0.12);
        color: #8e8e93;

        &:active {
          background: rgba(142, 142, 147, 0.25);
        }
      }

      .save-btn {
        background-color: #007aff;
        color: white;

        &:active {
          background-color: #0056cc;
        }

        &:disabled {
          opacity: 0.5;
          background-color: #c7c7cc;
        }
      }

      .tool-btn {
        background: rgba(0, 122, 255, 0.1);
        color: #007aff;

        &:active {
          background: rgba(0, 122, 255, 0.2);
        }
      }
    }

    .canvas-container {
      flex: 5; // 5:1 比例
      height: 100%;
      padding: 16px;

      .sign-canvas {
        width: 100%;
        height: 100%;
      }
    }

    .sign-tools {
      display: none; // 隐藏右下角工具栏
    }
  }

  .sign-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 16px;
    border-bottom: 1px solid #e5e5ea;
    background-color: #ffffff;

    .header-left,
    .header-right {
      min-width: 80px;
    }

    .header-title {
      font-size: 17px;
      font-weight: 600;
      color: #1d1d1f;
      text-align: center;
    }

    .close-btn {
      background: none;
      border: none;
      color: #8e8e93;
      font-size: 16px;
      font-weight: 500;
      padding: 8px 12px;
      border-radius: 8px;

      &:active {
        background-color: rgba(0, 0, 0, 0.05);
      }
    }

    .save-btn {
      background-color: #007aff;
      border: none;
      color: white;
      font-size: 16px;
      font-weight: 600;
      padding: 8px 16px;
      border-radius: 8px;

      &:active {
        background-color: #0056cc;
      }

      &:disabled {
        opacity: 0.5;
        background-color: #c7c7cc;
      }
    }
  }

  .canvas-container {
    flex: 1;
    padding: 16px;
    background-color: #f9f9f9;
    overflow: hidden;

    .sign-canvas {
      width: 100%;
      height: 100%;
      background-color: #ffffff;
      border: 1px dashed #e5e5ea;
      border-radius: 12px;
      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
    }
  }

  .sign-tools {
    display: flex;
    justify-content: space-around;
    padding: 16px;
    padding-bottom: 32px;
    background-color: #ffffff;
    border-top: 1px solid #e5e5ea;

    .tool-btn {
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 6px;
      padding: 12px 16px;
      border-radius: 12px;

      &:active {
        background-color: rgba(0, 0, 0, 0.05);
        transform: scale(0.95);
      }

      .tool-text {
        font-size: 14px;
        color: #007aff;
        font-weight: 500;
      }
    }
  }
}

// 进度弹窗
.progress-content {
  padding: 32px 24px;
  text-align: center;
  background: #ffffff;
  border-radius: 16px;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
  min-width: 200px;

  .progress-text {
    margin-top: 16px;
    font-size: 15px;
    color: #1d1d1f;
    font-weight: 500;
  }
}
</style>
